package com.neuedu.filter;

import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.alibaba.fastjson2.JSON;
import com.alibaba.nacos.shaded.com.google.gson.JsonObject;
import com.neuedu.entity.UmsStudent;
import com.neuedu.util.JwtUtil;
import com.neuedu.util.SystemUser;
import com.neuedu.vo.ResultJson;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Component
@ConfigurationProperties(prefix = "request.ignore")
public class AuthFilter implements GlobalFilter, Ordered {
    private List<String> urls;
    @Resource(name = "hjredistemplate")
    RedisTemplate<String, Object> redisTemplate;
    public void setUrls(List<String> urls) {
        this.urls = urls;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获取request和response
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        // 获取请求方式
        String method = request.getMethod().name();
        // 获取请求地址
        URI uri = request.getURI();
        String path = uri.getPath();
        // 有些情况，请求之前会先发一个OPTIONS请求，如果遇到OPTIONS请求，不用做任何事，直接通过
        if ("OPTIONS".equals(method)) {
            return chain.filter(exchange);
        }
        // 创建一个地址匹配工具
        AntPathMatcher matcher = new AntPathMatcher();
        // 循环白名单
        for (String url : urls) {
            // 如果当前请求和白名单匹配成功直接通过
            if (matcher.match(url, path)) {
                return chain.filter(exchange);
            }
        }
        // 如果不是白名单 获取token
        List<String> list = request.getHeaders().get("token");
        // 如果token拿不到，表示未登录
        if (null == list || list.isEmpty()) {
            return error(response, ResultJson.unauthorized("非法请求"));
        }
        // 获取token
        String token = list.get(0);
        SystemUser systemUser = null;
        try {
            // 校验token
            systemUser = JwtUtil.decode(token);
            String key = String.format("%s::%d", systemUser.getRole(), systemUser.getId());
            // 到缓存中查看是否存在
            if (!redisTemplate.hasKey(key)) {
                // 如果不存在表示登录超时
                return error(response, ResultJson.unauthorized("登录超时"));
            }
            // 重新失效时间
            redisTemplate.expire(key, 90, TimeUnit.MINUTES);
        } catch (Exception ex) {
            ex.printStackTrace();
            return error(response, ResultJson.unauthorized("非法请求"));
        }
        // 获取登录id
        Long login_id = systemUser.getId();
        // 将登录id 携带到controller
        StringBuilder new_query = new StringBuilder();
        String query = uri.getQuery();
        // 判断有没有query
        if (StringUtils.isNoneBlank(query)) {
            new_query.append(query).append("&");
        }
        // 将登录id 拼接到query中
        new_query.append("login_id=" + login_id);
        // 修改uri中的query , uri中的query是只读的，无法修改，必须重新构建 uri
        URI new_uri = UriComponentsBuilder.fromUri(uri).replaceQuery(new_query.toString()).build().toUri();
        // 修改request中的uri, request中的uri是只读的，无法修改，必须重新构建request
        ServerHttpRequest new_request = request.mutate().uri(new_uri).build();
        // 修改exchange中的request, exchange中的request是只读的，无法修改，必须重新构建exchange
        ServerWebExchange new_exchange = exchange.mutate().request(new_request).build();
        return chain.filter(new_exchange);
    }


    public Mono<Void> error(ServerHttpResponse response, ResultJson resultJson) {
        HttpHeaders headers = response.getHeaders();
        headers.set("Content-Type", "application/json;charset=utf-8");
        DataBuffer buffer = response.bufferFactory().wrap(JSON.toJSONString(resultJson).getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Flux.just(buffer));
    }
    @Override
    public int getOrder() {
        return 0;
    }
}
